/* Copyright 2008 Bas van den Berg
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <string>

#include "yaffut.h"
#include "myassert.h"
#include "TestSession.h"
#include "TestRoom.h"

#include "Area.h"
#include "MudExit.h"
#include "MudObject.h"
#include "MudPlayer.h"
#include "Parser.h"
#include "ParserFactory.h"
#include "color.h"

#include "Commands.h"

using namespace std;
using namespace Chronos;

class BlockerObject : public MudObject {
public:
    BlockerObject(const string& name) : MudObject(name, "descr") {}
    virtual void handleTrigger(MudTriggerAction action, MudMobile* cause, const std::string& msg) {
	    if (action == MESSAGE) cause->write(msg);
    }
};


class MovementCommandsTest {
public:
    MovementCommandsTest()
        : parser(*ParserFactory::create())
		, area(0, "")
        , session1("player1")
        , player1(session1.getPlayer())
    {
        loadArea();
        area.addPlayer(player1, 1, "");
        session1.clear();
        room1->clear();
    }
    ~MovementCommandsTest() {
		Room* room = player1.getRoom();
		room->removePlayer(player1, "");
        delete &parser;
    }
    void loadArea() {
        room1 = new TestRoom("NorthWest room");
        room1->addObject(new MudEastExit(area, 2));
        room1->addObject(new BlockerObject("blocker"));
        MudObject* blockedExit = new MudRoomExit("blockedExit", "", "arriveMsg", "leaveMsg", "enterMsg", area, 4);
        blockedExit->setVisible(false);
        blockedExit->addTrigger(MUDEXIT_PASS, "blocker", true, MESSAGE, "The blocker blocks you.");
        room1->addObject(blockedExit);
        area.addRoom(1, *room1);

        room2 = new TestRoom("NorthEast room");
        room2->addObject(new MudSouthExit(area, 4));
        area.addRoom(2, *room2);

        room3 = new TestRoom("SouthWest room");
        room3->addObject(new MudNorthExit(area, 1));
        area.addRoom(3, *room3);

        room4 = new TestRoom("SouthEast room");
        room4->addObject(new MudWestExit(area, 3));
        area.addRoom(4, *room4);
    }

    Parser& parser;
    Area area;
    TestRoom* room1;
    TestRoom* room2;
    TestRoom* room3;
    TestRoom* room4;

    TestSession session1;
    MudPlayer& player1;
};


TEST(MovementCommandsTest, testShouldMoveAllDirections) {
    // from room1 -> room2
    parser.parse(session1, "east");
    session1.SESSION_CHECKWRITTEN("NorthEast room ("ANSI_YELLOW"south"ANSI_NORMAL")\n");
    room1->ROOM_CHECKWRITTEN("player1 leaves east.\n");
    room2->ROOM_CHECKWRITTEN("player1 arrives from the west.\n");
    ASSERT_NULL(room1->findObject("player1"));
    ASSERT_NOT_NULL(room2->findObject("player1"));

    // from room2 -> room4
    parser.parse(session1, "south");
    session1.SESSION_CHECKWRITTEN("SouthEast room ("ANSI_YELLOW"west"ANSI_NORMAL")\n");
    room2->ROOM_CHECKWRITTEN("player1 leaves south.\n");
    room4->ROOM_CHECKWRITTEN("player1 arrives from the north.\n");
    ASSERT_NULL(room2->findObject("player1"));
    ASSERT_NOT_NULL(room4->findObject("player1"));
    
    // from room4 -> room3
    parser.parse(session1, "west");
    session1.SESSION_CHECKWRITTEN("SouthWest room ("ANSI_YELLOW"north"ANSI_NORMAL")\n");
    room4->ROOM_CHECKWRITTEN("player1 leaves west.\n");
    room3->ROOM_CHECKWRITTEN("player1 arrives from the east.\n");
    ASSERT_NULL(room4->findObject("player1"));
    ASSERT_NOT_NULL(room3->findObject("player1"));

    // from room3 -> room1
    parser.parse(session1, "north");
    session1.SESSION_CHECKWRITTEN("NorthWest room ("ANSI_YELLOW"east"ANSI_NORMAL")\n");
    room3->ROOM_CHECKWRITTEN("player1 leaves north.\n");
    room1->ROOM_CHECKWRITTEN("player1 arrives from the south.\n");
    ASSERT_NULL(room3->findObject("player1"));
    ASSERT_NOT_NULL(room1->findObject("player1"));
}


TEST(MovementCommandsTest, testBumpingIntoAWall) {
    parser.parse(session1, "north"); 
    session1.SESSION_CHECKWRITTEN("You can't go there.\n");
    ASSERT_NOT_NULL(room1->findObject("player1"));

    parser.parse(session1, "blocker");
    session1.SESSION_CHECKWRITTEN("What?!\n");
    ASSERT_NOT_NULL(room1->findObject("player1"));
}


TEST(MovementCommandsTest, testBlockedExit) {
    parser.parse(session1, "blockedExit");
    session1.SESSION_CHECKWRITTEN("The blocker blocks you.");
    ASSERT_NOT_NULL(room1->findObject("player1"));

    //TODO test when blocker object is not present
}


